
package chipyard_learning.mmio

import chisel3._
import chisel3.util._
import chisel3.experimental.{IntParam, BaseModule}
import freechips.rocketchip.amba.axi4._
import freechips.rocketchip.subsystem.BaseSubsystem
import org.chipsalliance.cde.config.{Parameters, Field, Config}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper.{HasRegMap, RegField}
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util.UIntIsOneOf
import org.w3c.dom.Node

case class JustReadParams(
  address: BigInt = 0x2000,
  width: Int = 32
)

case object JustReadKey extends Field[Option[JustReadParams]](None)


trait JustReadTopIO extends Bundle {
  val isReady = Output(Bool())
}

class JustReadIO (val w: Int) extends Bundle {
  val outPortToBeRead = Output(UInt(w.W))
}

trait HasJustReadIO extends BaseModule {
  val w: Int
  val io = IO(new JustReadIO(w))
}

class JustReadMMIOChiselModule(val w: Int) extends Module with HasJustReadIO {
  val a = RegInit(230.U(w.W))
  io.outPortToBeRead := a
}



trait JustReadTopModule extends HasRegMap{
  val io: JustReadTopIO
  implicit val p : Parameters
  def params: JustReadParams

  val isJustRead = Reg(UInt(params.width.W))

  val impl = Module(new JustReadMMIOChiselModule(params.width))

  isJustRead := impl.io.outPortToBeRead

  regmap(
    0x00 -> Seq(
      RegField.r(params.width, isJustRead) // r for read-only
    )
  )
}

class JustReadTL(params: JustReadParams, beatBytes: Int)(implicit p: Parameters) extends TLRegisterRouter(
  params.address, "justread", Seq("apaj, justreadit"),
  beatBytes = beatBytes
)(
  new TLRegBundle(params, _) with JustReadTopIO
)(
  new TLRegModule(params, _, _) with JustReadTopModule
)



trait CanHavePeripheryJustRead { this: BaseSubsystem =>
  private val portName = "justread"

  val justread = p(JustReadKey) match {
    case Some(params) => {
      val justread = LazyModule(new JustReadTL(params, pbus.beatBytes)(p))
      pbus.coupleTo(portName) {
        justread.node := TLFragmenter(pbus.beatBytes, pbus.blockBytes) := _
      }
      // pbus.toVariableWidthSlave(Some(portName)){justread.node}
      Some(justread)
    }
    case None => None
  }
}

trait CanHavePeripheryJustReadModuleImp extends LazyModuleImp {
  val outer: CanHavePeripheryJustRead
  // val justread_busy = outer.justread match {
  //   case Some(justread) => {
  //     val busy = IO(Output(Bool()))
  //     busy := justread.module.io.isReady
  //     Some(busy)
  //   }
  //   case None => None
  // }
}

class WithJustRead extends Config((site, here, up) => {
  case JustReadKey => Some(JustReadParams(address = 0x1000, width = 32))
})